home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / jobs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  21.2 KB  |  968 lines

  1. /*
  2.  * jobs.c - job control
  3.  *
  4.  * This file is part of zsh, the Z shell.
  5.  *
  6.  * This software is Copyright 1992 by Paul Falstad
  7.  *
  8.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  9.  * use this software as long as: there is no monetary profit gained
  10.  * specifically from the use or reproduction of this software, it is not
  11.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  12.  * included prominently in any copy made.
  13.  *
  14.  * The author make no claims as to the fitness or correctness of this software
  15.  * for any use whatsoever, and it is provided as is. Any use of this software
  16.  * is at the user's own risk.
  17.  *
  18.  */
  19.  
  20. #include "zsh.h"
  21. #include <errno.h>
  22. #include <setjmp.h>
  23.  
  24. #if defined(POSIX) && !defined(__386BSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
  25. # define JMP_BUF       sigjmp_buf
  26. # define SETJMP(b)     sigsetjmp((b), 1)
  27. # define LONGJMP(b,n)  siglongjmp((b), (n))
  28. #else
  29. # define JMP_BUF       jmp_buf
  30. # define SETJMP(b)     setjmp(b)
  31. # define LONGJMP(b,n)  longjmp((b), (n))
  32. #endif
  33.  
  34. #if defined(RESETHANDNEEDED) && !defined(POSIX)
  35. #define SIGPROCESS(sig)  sig_ignore(sig)
  36. #define SIGRESET(sig)    sig_handle(sig)
  37. #else
  38. #define SIGPROCESS(sig)  ;
  39. #define SIGRESET(sig)    ;
  40. #endif
  41.  
  42. /* empty job structure for quick clearing of jobtab entries */
  43.  
  44. static struct job zero; /* static variables are initialized to zero */
  45.  
  46. struct timeval dtimeval, now;
  47. struct timezone dummy_tz;
  48.  
  49. /* Diff two timevals for elapsed-time computations */
  50.  
  51. struct timeval *dtime(dt, t1, t2)    /**/
  52. struct timeval *dt;
  53. struct timeval *t1;
  54. struct timeval *t2;
  55. {
  56.     dt->tv_sec = t2->tv_sec - t1->tv_sec;
  57.     dt->tv_usec = t2->tv_usec - t1->tv_usec;
  58.     if (dt->tv_usec < 0) {
  59.     dt->tv_usec += 1000000;
  60.     dt->tv_sec -= 1;
  61.     }
  62.     return dt;
  63. }
  64.  
  65. /* do a safe, race-free sigpause() to wait for SIGCHLD */
  66.  
  67. static int chld_longjmp = 0;
  68. static struct z_jmp_buf {
  69.     JMP_BUF jbuf;
  70. } foil_race;
  71.  
  72. void chldhandler DCLPROTO((struct z_jmp_buf *jump));
  73.  
  74. void chldsuspend()
  75. {                /**/
  76. /* assumes blockchld() is in effect */
  77.     if (SETJMP(foil_race.jbuf) == 0) {
  78.     chld_longjmp = 1;
  79.     unblockchld();
  80.     chldpause();
  81.     }
  82.     chld_longjmp = 0;
  83. }
  84.  
  85. #ifdef INTHANDTYPE
  86. #define RETURN   { SIGRESET(sig); return 0; }
  87. #else
  88. #define RETURN   { SIGRESET(sig); return; }
  89. #endif
  90.  
  91. static int from_sig = 0;
  92.  
  93. /* the signal handler */
  94.  
  95. HANDTYPE handler(sig)        /**/
  96. int sig;
  97. {
  98.     sigset_t heldsigs;
  99.     int do_jump;
  100.     struct z_jmp_buf jump_to;
  101.  
  102.     SIGPROCESS(sig);
  103.  
  104.     fast_block(&heldsigs);    /* Prevent signal traps temporarily */
  105.  
  106.     do_jump = chld_longjmp;
  107.     chld_longjmp = 0;        /* In case a SIGCHLD somehow arrives */
  108.  
  109.     if (zigheld) {
  110.     zighold(sig, heldsigs);    /* zigsafe() will fast_unblock(&heldsigs) */
  111.     RETURN;
  112.     }
  113.     if (sig == SIGCHLD) {    /* Traps can cause nested chldsuspend() */
  114.     if (do_jump)
  115.         jump_to = foil_race;/* copy foil_race */
  116.     }
  117.  
  118.     fast_unblock(&heldsigs);    /* Signal traps OK again (foil_race copied) */
  119.  
  120.     switch (sig) {
  121.     case SIGHUP:
  122.     if (sigtrapped[SIGHUP])
  123.         dotrap(SIGHUP);
  124.     else {
  125.         stopmsg = 1;
  126.         from_sig = 1;
  127.         zexit(SIGHUP);
  128.     }
  129.     break;
  130.  
  131.     case SIGINT:
  132.     if (sigtrapped[SIGINT])
  133.         dotrap(SIGINT);
  134.     else {
  135.         breaks = loops;
  136.         errflag = 1;
  137.     }
  138.     break;
  139.  
  140. #if defined(SIGWINCH) && defined(TIOCGWINSZ)
  141.     case SIGWINCH:
  142.     adjustwinsize();
  143.     break;
  144. #endif
  145.  
  146.     case SIGCHLD:
  147.     chldhandler(do_jump ? &jump_to : (struct z_jmp_buf *)0);
  148.     RETURN;
  149.  
  150.     default:
  151.     dotrap(sig);
  152.     if (sig == SIGALRM) {
  153.         if (!sigtrapped[SIGALRM]) {
  154.         zerr("timeout", NULL, 0);
  155.         exit(1);
  156.         } else if (tmout) {
  157.         alarm(tmout);
  158.         }
  159.     }
  160.     break;
  161.     }
  162.  
  163.     RETURN;
  164. }
  165.  
  166. #undef RETURN
  167.  
  168. #define RETURN \
  169.     if (jump) { SIGRESET(SIGCHLD); LONGJMP(jump->jbuf, 1); } else return
  170.  
  171. void chldhandler(jump)
  172. struct z_jmp_buf *jump;
  173. {
  174.     long pid;
  175.     int statusp;
  176.     Job jn;
  177.     struct process *pn;
  178.  
  179. #ifdef HAS_RUSAGE
  180.     struct rusage ru;
  181.  
  182. #else
  183.     long chlds, chldu;
  184.  
  185. #endif
  186.  
  187.     for (;;) {
  188.     int old_errno = errno;
  189.  
  190. #ifdef HAS_RUSAGE
  191.     pid = wait3((vptr) & statusp, WNOHANG | WUNTRACED, &ru);
  192. #else
  193. #ifndef WNOHANG
  194.     pid = wait(&statusp);
  195. #else
  196. #ifdef HAS_WAITPID
  197.     pid = waitpid(-1, (vptr) & statusp, WNOHANG | WUNTRACED);
  198. #else
  199.     pid = wait3((vptr) & statusp, WNOHANG | WUNTRACED, NULL);
  200. #endif
  201. #endif
  202.     chlds = shtms.tms_cstime;
  203.     chldu = shtms.tms_cutime;
  204.     times(&shtms);
  205. #endif
  206.     if (pid == -1) {
  207.         if (errno != ECHILD)
  208.         zerr("wait failed: %e", NULL, errno);
  209.         errno = old_errno;
  210.         RETURN;
  211.     }
  212.     errno = old_errno;
  213.     if (!pid)
  214.         RETURN;
  215.     if (pid == cmdoutpid) {
  216.         cmdoutdone(statusp);
  217.         continue;
  218.     }
  219.     findproc(pid, &jn, &pn);/* find the process of this pid */
  220.     if (jn) {
  221.         pn->statusp = statusp;
  222. #ifdef HAS_RUSAGE
  223.         pn->ti.ru = ru;
  224. #else
  225.         pn->ti.st = shtms.tms_cstime - chlds;
  226.         pn->ti.ut = shtms.tms_cutime - chldu;
  227. #endif
  228.         gettimeofday(&pn->endtime, &dummy_tz);
  229.         updatestatus(jn);
  230.     }
  231. #if 0
  232.     else if (WIFSTOPPED(statusp))
  233.         kill(pid, SIGKILL);    /* kill stopped untraced children */
  234. #endif
  235.     }
  236. }
  237.  
  238. #undef RETURN
  239.  
  240. /* clean up after a $() or `` substitution */
  241.  
  242. void cmdoutdone(statusp)    /**/
  243. int statusp;
  244. {
  245.     cmdoutpid = 0;
  246.     if (WIFSIGNALED(statusp)) {
  247.     cmdoutval = (0200 | WTERMSIG(statusp));
  248.     if (WTERMSIG(statusp) == SIGINT)
  249.         (void)kill(getpid(), SIGINT);
  250.     else if (sigtrapped[WTERMSIG(statusp)])
  251.         dotrap(WTERMSIG(statusp));
  252.     } else
  253.     cmdoutval = WEXITSTATUS(statusp);
  254. }
  255.  
  256. /* change job table entry from stopped to running */
  257.  
  258. void makerunning(jn)        /**/
  259. Job jn;
  260. {
  261.     struct process *pn;
  262.  
  263.     jn->stat &= ~STAT_STOPPED;
  264.     for (pn = jn->procs; pn; pn = pn->next)
  265.     if (WIFSTOPPED(pn->statusp))
  266.         pn->statusp = SP_RUNNING;
  267. }
  268.  
  269. /* update status of job, possibly printing it */
  270.  
  271. void updatestatus(jn)        /**/
  272. Job jn;
  273. {
  274.     struct process *pn;
  275.     int notrunning = 1, alldone = 1, val = 0, job = jn - jobtab;
  276.     int statusp = 0, somestopped = 0, inforeground = 0;
  277.     int pgrp;
  278.  
  279.     pgrp = gettygrp();
  280.     for (pn = jn->procs; pn; pn = pn->next) {
  281.     if (pn->statusp == SP_RUNNING)
  282.         notrunning = 0;
  283.     if (pn->statusp == SP_RUNNING || WIFSTOPPED(pn->statusp))
  284.         alldone = 0;
  285.     if (WIFSTOPPED(pn->statusp))
  286.         somestopped = 1;
  287.     if (!pn->next && jn)
  288.         val = (WIFSIGNALED(pn->statusp)) ?
  289.         0200 | WTERMSIG(pn->statusp) : WEXITSTATUS(pn->statusp);
  290.     if (pn->pid == jn->gleader) {
  291.         statusp = pn->statusp;
  292.         if (pgrp == 0 || pn->pid == pgrp)
  293.           inforeground = 1;
  294.     }
  295.     }
  296.     if (!notrunning)
  297.     return;
  298.     if (somestopped) {
  299.     if (jn->stty_in_env && !jn->ty) {
  300.         jn->ty = (struct ttyinfo *)zalloc(sizeof(struct ttyinfo));
  301.         gettyinfo(jn->ty);
  302.     }
  303.     if (jn->stat & STAT_STOPPED)
  304.         return;
  305.     }
  306.     if (alldone && job == thisjob)
  307.     lastval = val;
  308.     if (inforeground && !ttyfrozen && !val && !jn->stty_in_env)
  309.     gettyinfo(&shttyinfo);
  310. #ifdef TIOCGWINSZ
  311.     adjustwinsize();
  312. #endif
  313.     jn->stat |= (alldone) ? STAT_CHANGED | STAT_DONE :
  314.     STAT_CHANGED | STAT_STOPPED;
  315.     if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) {
  316.     prevjob = curjob;
  317.     curjob = job;
  318.     }
  319.     if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) {
  320.     printjob(jn, !!isset(LONGLISTJOBS));
  321.     if (zleactive)
  322.         refresh();
  323.     }
  324.     if (sigtrapped[SIGCHLD] && job != thisjob)
  325.     dotrap(SIGCHLD);
  326.  
  327.     /* If the foreground job got a signal, pretend we got it, too. */
  328.     if (inforeground && WIFSIGNALED(statusp)) {
  329.     if (sigtrapped[WTERMSIG(statusp)]) {
  330.         dotrap(WTERMSIG(statusp));
  331.     } else if (WTERMSIG(statusp) == SIGINT ||
  332.            WTERMSIG(statusp) == SIGQUIT) {
  333.         breaks = loops;
  334.         errflag = 1;
  335.     }
  336.     }
  337. }
  338.  
  339. /* find process and job associated with pid */
  340.  
  341. void findproc(pid, jptr, pptr)    /**/
  342. int pid;
  343. Job *jptr;
  344. struct process **pptr;
  345. {
  346.     struct process *pn;
  347.     int jn;
  348.  
  349.     for (jn = 1; jn != MAXJOB; jn++)
  350.     for (pn = jobtab[jn].procs; pn; pn = pn->next)
  351.         if (pn->pid == pid) {
  352.         *pptr = pn;
  353.         *jptr = jobtab + jn;
  354.         return;
  355.         }
  356.     *pptr = NULL;
  357.     *jptr = NULL;
  358. }
  359.  
  360. /*
  361.     lng = 0 means jobs
  362.     lng = 1 means jobs -l
  363.     lng = 2 means jobs -p
  364. */
  365.  
  366. void printjob(jn, lng)        /**/
  367. Job jn;
  368. int lng;
  369. {
  370.     int job = jn - jobtab, len = 9, sig, sflag = 0, llen;
  371.     int conted = 0, lineleng = columns, skip = 0, doputnl = 0;
  372.     struct process *pn;
  373.  
  374.     if (lng < 0) {
  375.     conted = 1;
  376.     lng = 0;
  377.     }
  378. /* find length of longest signame, check to see if we
  379.         really need to print this job */
  380.  
  381.     for (pn = jn->procs; pn; pn = pn->next) {
  382.     if (pn->statusp != SP_RUNNING)
  383.         if (WIFSIGNALED(pn->statusp)) {
  384.         sig = WTERMSIG(pn->statusp);
  385.         llen = strlen(sigmsg[sig]);
  386.         if (WCOREDUMP(pn->statusp))
  387.             llen += 14;
  388.         if (llen > len)
  389.             len = llen;
  390.         if (sig != SIGINT && sig != SIGPIPE)
  391.             sflag = 1;
  392.         else if (sig == SIGINT)
  393.             errflag = 1;
  394.         if (job == thisjob && sig == SIGINT)
  395.             doputnl = 1;
  396.         } else if (WIFSTOPPED(pn->statusp)) {
  397.         sig = WSTOPSIG(pn->statusp);
  398.         if ((int) strlen(sigmsg[sig]) > len)
  399.             len = strlen(sigmsg[sig]);
  400.         if (job == thisjob && sig == SIGTSTP)
  401.             doputnl = 1;
  402.         } else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
  403.                WEXITSTATUS(pn->statusp))
  404.         sflag = 1;
  405.     }
  406.  
  407. /* print if necessary */
  408.  
  409.     if (interact && jobbing && ((jn->stat & STAT_STOPPED) || sflag ||
  410.                 job != thisjob)) {
  411.     int len2, fline = 1;
  412.     struct process *qn;
  413.  
  414.     trashzle();
  415.     if (doputnl)
  416.         putc('\n', stderr);
  417.     for (pn = jn->procs; pn;) {
  418.         len2 = ((job == thisjob) ? 5 : 10) + len;    /* 2 spaces */
  419.         if (lng)
  420.         qn = pn->next;
  421.         else
  422.         for (qn = pn->next; qn; qn = qn->next) {
  423.             if (qn->statusp != pn->statusp)
  424.             break;
  425.             if ((int) strlen(qn->text) + len2 + ((qn->next) ? 3 : 0) > lineleng)
  426.             break;
  427.             len2 += strlen(qn->text) + 2;
  428.         }
  429.         if (job != thisjob)
  430.         if (fline)
  431.             fprintf(stderr, "[%ld]  %c ",
  432.                 (long)(jn - jobtab),
  433.                 (job == curjob) ? '+'
  434.                  : (job == prevjob) ? '-' : ' ');
  435.         else
  436.             fprintf(stderr, (job > 9) ? "        " : "       ");
  437.         else
  438.         fprintf(stderr, "zsh: ");
  439.         if (lng)
  440.         if (lng == 1)
  441.             fprintf(stderr, "%ld ", pn->pid);
  442.         else {
  443.             int x = jn->gleader;
  444.  
  445.             fprintf(stderr, "%d ", x);
  446.             do
  447.             skip++;
  448.             while ((x /= 10));
  449.             skip++;
  450.             lng = 0;
  451.         } else
  452.         fprintf(stderr, "%*s", skip, "");
  453.         if (pn->statusp == SP_RUNNING)
  454.         if (!conted)
  455.             fprintf(stderr, "running%*s", len - 7 + 2, "");
  456.         else
  457.             fprintf(stderr, "continued%*s", len - 9 + 2, "");
  458.         else if (WIFEXITED(pn->statusp))
  459.         if (WEXITSTATUS(pn->statusp))
  460.             fprintf(stderr, "exit %-4d%*s", WEXITSTATUS(pn->statusp),
  461.                 len - 9 + 2, "");
  462.         else
  463.             fprintf(stderr, "done%*s", len - 4 + 2, "");
  464.         else if (WIFSTOPPED(pn->statusp))
  465.         fprintf(stderr, "%-*s", len + 2, sigmsg[WSTOPSIG(pn->statusp)]);
  466.         else if (WCOREDUMP(pn->statusp))
  467.         fprintf(stderr, "%s (core dumped)%*s",
  468.             sigmsg[WTERMSIG(pn->statusp)],
  469.             (int)(len - 14 + 2 - strlen(sigmsg[WTERMSIG(pn->statusp)])), "");
  470.         else
  471.         fprintf(stderr, "%-*s", len + 2, sigmsg[WTERMSIG(pn->statusp)]);
  472.         for (; pn != qn; pn = pn->next)
  473.         fprintf(stderr, (pn->next) ? "%s | " : "%s", pn->text);
  474.         putc('\n', stderr);
  475.         fline = 0;
  476.     }
  477.     } else if (doputnl && interact)
  478.     putc('\n', stderr);
  479.     fflush(stderr);
  480.  
  481. /* print "(pwd now: foo)" messages */
  482.  
  483.     if (interact && job == thisjob && strcmp(jn->pwd, pwd)) {
  484.     printf("(pwd now: ");
  485.     printdir(pwd);
  486.     printf(")\n");
  487.     fflush(stdout);
  488.     }
  489. /* delete job if done */
  490.  
  491.     if (jn->stat & STAT_DONE) {
  492.     if ((jn->stat & STAT_TIMED) || (reporttime != -1 && report(jn))) {
  493.         dumptime(jn);
  494.     }
  495.     deletejob(jn);
  496.     if (job == curjob) {
  497.         curjob = prevjob;
  498.         prevjob = job;
  499.     }
  500.     if (job == prevjob)
  501.         setprevjob();
  502.     } else
  503.     jn->stat &= ~STAT_CHANGED;
  504. }
  505.  
  506. void deletejob(jn)        /**/
  507. Job jn;
  508. {
  509.     struct process *pn, *nx;
  510.     char *s;
  511.  
  512.     for (pn = jn->procs; pn; pn = nx) {
  513.     nx = pn->next;
  514.     zfree(pn, sizeof(struct process));
  515.     }
  516.     zsfree(jn->pwd);
  517.     if (jn->filelist) {
  518.     while ((s = (char *)getnode(jn->filelist))) {
  519.         unlink(s);
  520.         zsfree(s);
  521.     }
  522.     zfree(jn->filelist, sizeof(struct lklist));
  523.     }
  524.     if (jn->ty)
  525.     zfree(jn->ty, sizeof(struct ttyinfo));
  526.     *jn = zero;
  527. }
  528.  
  529. /* set the previous job to something reasonable */
  530.  
  531. void setprevjob()
  532. {                /**/
  533.     int t0;
  534.  
  535.     for (t0 = MAXJOB - 1; t0; t0--)
  536.     if ((jobtab[t0].stat & STAT_INUSE) && (jobtab[t0].stat & STAT_STOPPED) &&
  537.         t0 != curjob && t0 != thisjob)
  538.         break;
  539.     if (!t0)
  540.     for (t0 = MAXJOB - 1; t0; t0--)
  541.         if ((jobtab[t0].stat & STAT_INUSE) && t0 != curjob && t0 != thisjob)
  542.         break;
  543.     prevjob = (t0) ? t0 : -1;
  544. }
  545.  
  546. /* initialize a job table entry */
  547.  
  548. void initjob()
  549. {                /**/
  550.     jobtab[thisjob].pwd = ztrdup(pwd);
  551.     jobtab[thisjob].stat = STAT_INUSE;
  552.     jobtab[thisjob].gleader = 0;
  553. }
  554.  
  555. /* add a process to the current job */
  556.  
  557. void addproc(pid, text)    /**/
  558. long pid;
  559. char *text;
  560. {
  561.     struct process *process;
  562.  
  563.     if (!jobtab[thisjob].gleader)
  564.     jobtab[thisjob].gleader = pid;
  565.     process = (struct process *)zcalloc(sizeof *process);
  566.     process->pid = pid;
  567.     if (text)
  568.     strcpy(process->text, text);
  569.     else
  570.     *process->text = '\0';
  571.     process->next = NULL;
  572.     process->statusp = SP_RUNNING;
  573.     gettimeofday(&process->bgtime, &dummy_tz);
  574.     if (jobtab[thisjob].procs) {
  575.     struct process *n;
  576.  
  577.     for (n = jobtab[thisjob].procs; n->next; n = n->next);
  578.     process->next = NULL;
  579.     n->next = process;
  580.     } else
  581.     jobtab[thisjob].procs = process;
  582. }
  583.  
  584. /* determine if it's all right to exec a command without
  585.     forking in last component of subshells; it's not ok if we have files
  586.     to delete */
  587.  
  588. int execok()
  589. {                /**/
  590.     Job jn;
  591.  
  592.     if (!exiting)
  593.     return 0;
  594.     for (jn = jobtab + 1; jn != jobtab + MAXJOB; jn++)
  595.     if (jn->stat && jn->filelist)
  596.         return 0;
  597.     return 1;
  598.  
  599. }
  600.  
  601. void waitforpid(pid)        /**/
  602. long pid;
  603. {
  604. /* blockchld() around this loop in case #ifndef WNOHANG */
  605.     blockchld();        /* unblocked in chldsuspend() */
  606.     while (!errflag && (kill(pid, 0) >= 0 || errno != ESRCH)) {
  607.     chldsuspend();
  608.     blockchld();
  609.     }
  610.     unblockchld();
  611. }
  612.  
  613. /* wait for a job to finish */
  614.  
  615. void waitjob(job)        /**/
  616. int job;
  617. {
  618.     Job jn = jobtab + job;
  619.  
  620.     blockchld();        /* unblocked during chldsuspend() */
  621.     if (jn->procs) {    /* if any forks were done */
  622.     jn->stat |= STAT_LOCKED;
  623.     if (jn->stat & STAT_CHANGED)
  624.         printjob(jobtab + job, !!isset(LONGLISTJOBS));
  625.     while (jn->stat &&
  626.            !(jn->stat & STAT_DONE) &&
  627.            !(interact && (jn->stat & STAT_STOPPED)))
  628.     {
  629.         chldsuspend();
  630.         blockchld();
  631.     }
  632.     } else
  633.     deletejob(jobtab + job);
  634.     unblockchld();
  635. }
  636.  
  637. /* wait for running job to finish */
  638.  
  639. void waitjobs()
  640. {                /**/
  641.     waitjob(thisjob);
  642.     thisjob = -1;
  643. }
  644.  
  645. /* clear job table when entering subshells */
  646.  
  647. void clearjobtab()
  648. {                /**/
  649.     int t0;
  650.  
  651.     for (t0 = 1; t0 != MAXJOB; t0++) {
  652.     if (jobtab[t0].pwd)
  653.         zsfree(jobtab[t0].pwd);
  654.     if (jobtab[t0].ty)
  655.         zfree(jobtab[t0].ty, sizeof(struct ttyinfo));
  656.     jobtab[t0] = zero;
  657.     }
  658. }
  659.  
  660. /* get a free entry in the job table to use */
  661.  
  662. int getfreejob()
  663. {                /**/
  664.     int t0;
  665.  
  666.     for (t0 = 1; t0 != MAXJOB; t0++)
  667.     if (!jobtab[t0].stat) {
  668.         jobtab[t0].stat |= STAT_INUSE;
  669.         return t0;
  670.     }
  671.     zerr("job table full or recursion limit exceeded", NULL, 0);
  672.     return -1;
  673. }
  674.  
  675. /* print pids for & */
  676.  
  677. void spawnjob()
  678. {                /**/
  679.     struct process *pn;
  680.  
  681.     if (!subsh) {
  682.     if (curjob == -1 || !(jobtab[curjob].stat & STAT_STOPPED)) {
  683.         curjob = thisjob;
  684.         setprevjob();
  685.     } else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
  686.         prevjob = thisjob;
  687.     if (interact && jobbing && jobtab[thisjob].procs) {
  688.         fprintf(stderr, "[%d]", thisjob);
  689.         for (pn = jobtab[thisjob].procs; pn; pn = pn->next)
  690.         fprintf(stderr, " %ld", pn->pid);
  691.         fprintf(stderr, "\n");
  692.         fflush(stderr);
  693.     }
  694.     }
  695.     if (!jobtab[thisjob].procs)
  696.     deletejob(jobtab + thisjob);
  697.     else
  698.     jobtab[thisjob].stat |= STAT_LOCKED;
  699.     thisjob = -1;
  700. }
  701.  
  702. int report(j)            /**/
  703. Job j;
  704. {
  705.     if (!j->procs)
  706.     return 0;
  707. #ifdef HAS_RUSAGE
  708.     return (j->procs->ti.ru.ru_utime.tv_sec + j->procs->ti.ru.ru_stime.tv_sec)
  709.     >= reporttime;
  710. #else
  711.     return (j->procs->ti.ut + j->procs->ti.st) / HZ >= reporttime;
  712. #endif
  713. }
  714.  
  715. void printtime(real, ti, desc)    /**/
  716. struct timeval *real;
  717. struct timeinfo *ti;
  718. char *desc;
  719. {
  720.     char *s;
  721.     long real100;
  722.  
  723. #ifdef HAS_RUSAGE
  724. #ifdef sun
  725.     long ticks = 1;
  726.     int pk = getpagesize() / 1024;
  727.  
  728. #else
  729.     long sec;
  730.  
  731. #endif
  732.     struct rusage *ru = &ti->ru;
  733.  
  734. #endif
  735.  
  736.     if (!desc)
  737.     desc = "";
  738. #ifdef HAS_RUSAGE
  739. #ifdef sun
  740.     ticks = (ru->ru_utime.tv_sec + ru->ru_stime.tv_sec) * HZ +
  741.     (ru->ru_utime.tv_usec + ru->ru_stime.tv_usec) * HZ / 1000000;
  742.     if (!ticks)
  743.     ticks = 1;
  744. #else
  745.     sec = ru->ru_utime.tv_sec + ru->ru_stime.tv_sec;
  746.     if (!sec)
  747.     sec = 1;
  748. #endif
  749. #endif
  750.     for (s = timefmt; *s; s++)
  751.     if (*s == '%')
  752.         switch (s++, *s) {
  753.         case 'E':
  754.         fprintf(stderr, "%ld.%03lds",
  755.             (long) real->tv_sec, (long) real->tv_usec / 1000);
  756.         break;
  757. #ifndef HAS_RUSAGE
  758.         case 'U':
  759.         fprintf(stderr, "%ld.%03lds",
  760.             ti->ut / HZ, ti->ut * 1000 / HZ % 1000);
  761.         break;
  762.         case 'S':
  763.         fprintf(stderr, "%ld.%03lds",
  764.             ti->st / HZ, ti->st * 1000 / HZ % 1000);
  765.         break;
  766.         case 'P':
  767.       if ( real->tv_sec > 21000 ) {
  768.          real100 = (real->tv_sec + 99)/100;
  769.             fprintf(stderr, "%d%%",
  770.                  (int)((ti->ut + ti->st) / HZ)/real100);
  771.       }
  772.       else {
  773.          if (( real100 = real->tv_sec * 1000 + real->tv_usec / 1000 ))
  774.             fprintf(stderr, "%d%%",
  775.                     (int)(100000 * ((ti->ut + ti->st) / HZ)) / real100);
  776.       }
  777.         break;
  778. #else
  779.         case 'U':
  780.         fprintf(stderr, "%ld.%03lds",
  781.             (long) ru->ru_utime.tv_sec,
  782.             (long) ru->ru_utime.tv_usec / 1000);
  783.         break;
  784.         case 'S':
  785.         fprintf(stderr, "%ld.%03lds",
  786.             (long) ru->ru_stime.tv_sec,
  787.             (long) ru->ru_stime.tv_usec / 1000);
  788.         break;
  789.         case 'P':
  790.       if ( real->tv_sec > 21000 ) {
  791.          real100 = (real->tv_sec + 99)/100;
  792.             fprintf(stderr, "%ld%%",
  793.                  (ru->ru_utime.tv_sec + ru->ru_stime.tv_sec)/real100);
  794.       }
  795.       else {
  796.          if (( real100 = real->tv_sec * 1000 + real->tv_usec / 1000 ))
  797.             fprintf(stderr, "%ld%%",
  798.                     (100000 * (ru->ru_utime.tv_sec + ru->ru_stime.tv_sec)
  799.                  + 
  800.                      (ru->ru_utime.tv_usec + ru->ru_stime.tv_usec) / 10)
  801.                     / real100);
  802.       }
  803.         break;
  804.         case 'W':
  805.         fprintf(stderr, "%ld", ru->ru_nswap);
  806.         break;
  807. #ifdef sun
  808.         case 'K':
  809.         case 'D':
  810.         fprintf(stderr, "%ld", ru->ru_idrss / ticks * pk);
  811.         break;
  812.         case 'M':
  813.         fprintf(stderr, "%ld", ru->ru_maxrss * pk);
  814.         break;
  815. #else
  816.         case 'X':
  817.         fprintf(stderr, "%ld", ru->ru_ixrss / sec);
  818.         break;
  819.         case 'D':
  820.         fprintf(stderr, "%ld",
  821.             (ru->ru_idrss + ru->ru_isrss) / sec);
  822.         break;
  823.         case 'K':
  824.         fprintf(stderr, "%ld",
  825.             (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / sec);
  826.         break;
  827.         case 'M':
  828.         fprintf(stderr, "%ld", ru->ru_maxrss / 1024);
  829.         break;
  830. #endif
  831.         case 'F':
  832.         fprintf(stderr, "%ld", ru->ru_majflt);
  833.         break;
  834.         case 'R':
  835.         fprintf(stderr, "%ld", ru->ru_minflt);
  836.         break;
  837.         case 'I':
  838.         fprintf(stderr, "%ld", ru->ru_inblock);
  839.         break;
  840.         case 'O':
  841.         fprintf(stderr, "%ld", ru->ru_oublock);
  842.         break;
  843.         case 'r':
  844.         fprintf(stderr, "%ld", ru->ru_msgrcv);
  845.         break;
  846.         case 's':
  847.         fprintf(stderr, "%ld", ru->ru_msgsnd);
  848.         break;
  849.         case 'k':
  850.         fprintf(stderr, "%ld", ru->ru_nsignals);
  851.         break;
  852.         case 'w':
  853.         fprintf(stderr, "%ld", ru->ru_nvcsw);
  854.         break;
  855.         case 'c':
  856.         fprintf(stderr, "%ld", ru->ru_nivcsw);
  857.         break;
  858. #endif
  859.         case 'J':
  860.         fprintf(stderr, "%s", desc);
  861.         break;
  862.         default:
  863.         fprintf(stderr, "%%%c", *s);
  864.         break;
  865.     } else
  866.         putc(*s, stderr);
  867.     putc('\n', stderr);
  868.     fflush(stderr);
  869. }
  870.  
  871. void dumptime(jn)        /**/
  872. Job jn;
  873. {
  874.     struct process *pn;
  875.  
  876.     if (!jn->procs)
  877.     return;
  878.     for (pn = jn->procs; pn; pn = pn->next)
  879.     printtime(dtime(&dtimeval, &pn->bgtime, &pn->endtime), &pn->ti, pn->text);
  880. }
  881.  
  882. void shelltime()
  883. {                /**/
  884.     struct timeinfo ti;
  885.  
  886. #ifdef HAS_RUSAGE
  887.     struct rusage ru;
  888.  
  889.     getrusage(RUSAGE_SELF, &ru);
  890.     memcpy(&ti.ru, &ru, sizeof(ru));
  891.     gettimeofday(&now, &dummy_tz);
  892.     printtime(dtime(&dtimeval, &shtimer, &now), &ti, "shell");
  893.  
  894.     getrusage(RUSAGE_CHILDREN, &ru);
  895.     memcpy(&ti.ru, &ru, sizeof(ru));
  896.     printtime(dtime(&dtimeval, &shtimer, &now), &ti, "children");
  897. #else
  898.     struct tms buf;
  899.  
  900.     times(&buf);
  901.     ti.ut = buf.tms_utime;
  902.     ti.st = buf.tms_stime;
  903.     gettimeofday(&now, &dummy_tz);
  904.     printtime(dtime(&dtimeval, &shtimer, &now), &ti, "shell");
  905.     ti.ut = buf.tms_cutime;
  906.     ti.st = buf.tms_cstime;
  907.     printtime(dtime(&dtimeval, &shtimer, &now), &ti, "children");
  908. #endif
  909. }
  910.  
  911. /* SIGHUP any jobs left running */
  912.  
  913. void killrunjobs()
  914. {                /**/
  915.     int t0, killed = 0;
  916.  
  917.     if (isset(NOHUP))
  918.     return;
  919.     for (t0 = 1; t0 != MAXJOB; t0++)
  920.     if ((from_sig || t0 != thisjob) && (jobtab[t0].stat & STAT_LOCKED) &&
  921.         !(jobtab[t0].stat & STAT_STOPPED)) {
  922.         if (killpg(jobtab[t0].gleader, SIGHUP) != -1)
  923.         killed++;
  924.     }
  925.     if (killed)
  926.     zerr("warning: %d jobs SIGHUPed", NULL, killed);
  927. }
  928.  
  929. /* check to see if user has jobs running/stopped */
  930.  
  931. void checkjobs()
  932. {                /**/
  933.     int t0;
  934.  
  935.     scanjobs();
  936.     for (t0 = 1; t0 != MAXJOB; t0++)
  937.     if (t0 != thisjob && jobtab[t0].stat & STAT_LOCKED)
  938.         break;
  939.     if (t0 != MAXJOB) {
  940.     if (jobtab[t0].stat & STAT_STOPPED) {
  941. #ifdef USE_SUSPENDED
  942.         zerr("you have suspended jobs.", NULL, 0);
  943. #else
  944.         zerr("you have stopped jobs.", NULL, 0);
  945. #endif
  946.     } else
  947.         zerr("you have running jobs.", NULL, 0);
  948.     stopmsg = 1;
  949.     }
  950. }
  951.  
  952. /* send a signal to a job (simply involves kill if monitoring is on) */
  953.  
  954. int killjb(jn, sig)        /**/
  955. Job jn;
  956. int sig;
  957. {
  958.     struct process *pn;
  959.     int err = 0;
  960.  
  961.     if (jobbing)
  962.     return (killpg(jn->gleader, sig));
  963.     for (pn = jn->procs; pn; pn = pn->next)
  964.     if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH)
  965.         return -1;
  966.     return err;
  967. }
  968.